package com.yuandian.customer.perception.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.feign.RemoteImportanceOperatorService;
import com.yuandian.api.customer_perception.po.*;
import com.yuandian.api.customer_perception.vo.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.data.resolver.ParamResolver;
import com.yuandian.customer.perception.mapper.ImportanceOperatorExtendMapper;
import com.yuandian.customer.perception.mapper.ImportanceOperatorMapper;
import com.yuandian.customer.perception.service.IImportanceOperatorService;
import com.yuandian.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 重点用户
 *
 * @Author wangpeiyang
 * @Date 2021/5/17 17:52
 */
@Service
public class ImportanceOperatorServiceImpl extends ServiceImpl<ImportanceOperatorMapper, ImportanceOperator>
		implements IImportanceOperatorService {

    @Resource
	ImportanceOperatorExtendMapper importanceOperatorExtendMapper;

	@Autowired
	private ImportanceOperatorMapper importanceOperatorMapper;

	@Autowired
	private RemoteImportanceOperatorService remoteImportanceOperatorService;



    /**
     * 重点用户-最新告警 
     */ 
    public LastAlarmVo queryLastAlarm(LastAlarmParams params) {
        return importanceOperatorExtendMapper.queryLastAlarm(params);
    }

    /**
     * 重点用户-业务系统健康度 
     */ 
    public R<Object> queryBusinessHealthRate(BusinessHealthRateParams params) {
        String tableNameSuffix = LocalDate.now().format(DateTimeFormatter.ofPattern(YDateUtil.YYYYMMDD));
        String tableName = "busi_sys_detail_stat_m_" + tableNameSuffix;
        params.setTableName(tableName);
        return  R.ok(importanceOperatorExtendMapper.queryBusinessHealthRate(params));
    }

    /**
     * 重点用户-告警趋势 
     */
    @Override
    public R<Object> queryAlarmTrendList(AlarmTrendParams params) {
        String tableNameSuffix = LocalDate.now().format(DateTimeFormatter.ofPattern(YDateUtil.YYYYMMDD));
        String tableName = "busi_base_alarm_stat_m_" + tableNameSuffix;
        params.setTableName(tableName);
        List<AlarmTrendVo> list = importanceOperatorExtendMapper.queryAlarmTrendList(params);
        // 计算时间标签
        Map<String, List<AlarmTrendVo>> map = DataBelongUtil
                .dataBelong(params.getEndTime(), 2, list, AlarmTrendVo.class);
        List<AlarmTrendVo> result = new ArrayList<>();
        map.forEach((labelTime, voList) -> {
            AlarmTrendVo r = new AlarmTrendVo();
            r.setAlarmCount(0);
            voList.forEach(vo -> {
                r.setAlarmCount(r.getAlarmCount() + vo.getAlarmCount());
            });
            if (DateTool.compare(params.getEndTime(), labelTime) < 0) {
                r.setAlarmCount(null);
            }
            r.setCycleTime(labelTime);
            result.add(r);
        });
        //去掉最后一个点使趋势图不掉底,会导致最后刻度不是当前时间
        if (result.size() > 1) {
            result.remove(result.size() - 1);
        }
        return  R.ok(result);
    }

    /**
     * 重点用户-告警统计
     */
    @Override
    public R<PageDataInfo> queryAlarmList(AlarmParams params) {
        List<AlarmVo> list = new ArrayList<>();
        long totalHits = 0;
        // 设置重点用户id
		List<ImportanceOperator> importanceOperatorList = remoteImportanceOperatorService.getImportanceOperatorList(params.getName(), "0", params.getOperatorId()).getData();

        if (importanceOperatorList.isEmpty()) { return R.ok(new PageDataInfo(totalHits, list)); }

        try {
			Page<AlarmVo> page = new Page<>(params.getPageNum(), params.getPageSize());
			params.setOperatorIds(getImportanceOperatorIds(importanceOperatorList));
			list = importanceOperatorExtendMapper.queryAlarmList(page, params);

			// 7.回填重点人员信息
			Map<String, ImportanceOperator> importanceOperatorMap = getImportanceOperatorMap(importanceOperatorList);
			for (AlarmVo alarm : list) {
				ImportanceOperator operator = importanceOperatorMap.get(alarm.getOperatorId());
				if (operator != null) {
					alarm.setName(operator.getName());
					alarm.setDepartment(operator.getDepartment());
					alarm.setRemarks(operator.getRemark());
				}
			}

        } catch (Exception e) {
            log.error("重点用户-告警统计查询错误", e);
            return R.failed("重点用户-告警统计查询错误");
        }
        return  R.ok(new PageDataInfo(totalHits, list));
    }

	@Override
	public R<PageDataInfo> findByPager(ImportanceOperatorParams params) {
		Map<String, Object> param= new HashMap<>();
		param.put("page", (params.getPageNum()-1) * params.getPageSize());
		param.put("size", params.getPageSize());
		param.put("operatorId", params.getOperatorId());
		param.put("name", params.getName());
		return remoteImportanceOperatorService.findByPager(params);
	}

	/**
     * 实时告警姓名下拉框接口
     *
     * @return 实时告警重点用户姓名数据
     */
    @Override
    public List<SearchOptionVo> operatorNameSearchOption() {
        List<SearchOptionVo> result = new ArrayList<>();
        List<ImportanceOperator> list = this.list();
        list.forEach(importanceOperator -> {
            SearchOptionVo vo = new SearchOptionVo();
            if (importanceOperator.getName() != null && !("").equals(importanceOperator.getName())) {
                vo.setLabel(importanceOperator.getName());
                vo.setValue(importanceOperator.getName());
                result.add(vo);
            }
        });
        return result;
    }

    /**
     * 实时告警用户名下拉框接口
     *
     * @return 实时告警重点用户姓名数据
     */
    @Override
    public List<SearchOptionVo> operatorIdSearchOption() {
        List<SearchOptionVo> result = new ArrayList<>();
        List<ImportanceOperator> list = this.list();
        list.forEach(importanceOperator -> {
            SearchOptionVo vo = new SearchOptionVo();
            if (importanceOperator.getName() != null && !("").equals(importanceOperator.getName())) {
                vo.setLabel(importanceOperator.getOperatorId());
                vo.setValue(importanceOperator.getOperatorId());
                result.add(vo);
            }
        });
        return result;
    }

    /**
     * 重点用户实时使用情况列表 
     */
     @Override
    public R<Object> importanceOperatorRealTimeUsage(Integer systemId) {
        ArrayList<RealTimeOperateVo> result = new ArrayList<>();
        // 查出重点用户
        List<ImportanceOperator> importanceOperatorList = this.lambdaQuery()
                .eq(ImportanceOperator::getStatus, 0)
                .orderByAsc(ImportanceOperator::getId)
                .list();
        if (importanceOperatorList.size() == 0) {
            return  R.ok(result);
        }

        // 根据重点用户查当天用户最新业务详单
        String tableName = "business_detail_" + LocalDate.now().format(DateTimeFormatter.ofPattern(YDateUtil.YYYYMMDD));
        String[] fields = {
                "operatorId","businessName", "lastStepName", "endTime"
        };
        try {
            List<String> operators=new ArrayList<>();
            importanceOperatorList.forEach(importanceOperator -> {
                operators.add(importanceOperator.getOperatorId());
            });

			ImportanceOperatorParams params = new ImportanceOperatorParams();
			params.setOperatorIdList(operators);
			params.setSystemId(systemId);
			params.setOrderByColumn("endTime");
			params.setIsAsc("desc");

			// 只查不完整的
			String uncompleted = ParamResolver.getStr("khgz.important.complete.configuration");
			if ("uncompleted".equals(uncompleted)) { params.setCompletionState("0"); }
			// 计算分区
			String partition = PartitionUtil.getPartitionBasedOnTime(DateUtil.formatDateTime(new Date()));

			// 查询数据
			List<RealTimeOperateVo> realTimeOperateVos = importanceOperatorExtendMapper.queryRealTimeOperateList(params, partition);

			if (realTimeOperateVos.size() > 0) {

				//6.组装数据
				HashMap<String,String> timeMap = new HashMap<>();
				HashMap<String,String> businessNameMap = new HashMap<>();
				HashMap<String,String> lastStepNameMap = new HashMap<>();

				for (RealTimeOperateVo realTimeOperateVo : realTimeOperateVos) {

					if (realTimeOperateVo.getOperatorId() == null){
						timeMap.put(realTimeOperateVo.getOperatorId(),  realTimeOperateVo.getEndTime());
						businessNameMap.put(realTimeOperateVo.getOperatorId(), realTimeOperateVo.getBusinessName());
						lastStepNameMap.put(realTimeOperateVo.getOperatorId(), realTimeOperateVo.getLastStepName());

					} else {
						long timeMapEnd = LocalDateTime.parse(timeMap.get(realTimeOperateVo.getOperatorId()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
						long mapEndTime = LocalDateTime.parse(realTimeOperateVo.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
						if (mapEndTime > timeMapEnd){
							timeMap.put(realTimeOperateVo.getOperatorId(), realTimeOperateVo.getEndTime());
							businessNameMap.put(realTimeOperateVo.getOperatorId(), realTimeOperateVo.getBusinessName());
							lastStepNameMap.put(realTimeOperateVo.getOperatorId(), realTimeOperateVo.getLastStepName());
						}
					}
				}

				for (ImportanceOperator operator : importanceOperatorList) {
					if (!StringUtils.isEmpty(timeMap.get(operator.getOperatorId()))) {
						RealTimeOperateVo vo = BeanUtils.convert(operator, RealTimeOperateVo.class);
						if (timeMap.get(operator.getOperatorId())!=null){
						// 计算endTime到现在的时间
						long endMilliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
						long startMilliSecond = LocalDateTime.parse(timeMap.get(operator.getOperatorId()), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
						vo.setDealTime((int) (endMilliSecond - startMilliSecond));
						vo.setBusinessName(businessNameMap.get(operator.getOperatorId()));
						vo.setStepName(lastStepNameMap.get(operator.getOperatorId()));
						result.add(vo);
						}
					}
				}
			}
        } catch (
                Exception e) {
            log.error("重点用户-用户实时使用情况列表查询错误", e);
            return R.failed("查询出错");
        }
        return  R.ok(result);
    }

    /**
     * 用户操作轨迹
     */
    @Override
    public R<Object> operateTrajectory(OperateTrajectoryParams params) {

        // 根据重点用户查当天用户最新业务详单
		Page<OperateTrajectoryVo> page = new Page<>(params.getPageNum(), params.getPageSize());
		List<OperateTrajectoryVo> operateTrajectoryVos = importanceOperatorExtendMapper.queryOperateTrajectoryList(page, params);

        return  R.ok(new PageDataInfo(page, operateTrajectoryVos));
    }

    /**
     * 查询用户所有操作轨迹
     */
    @Override
    public R<Object> operateAllTrajectory(OperateTrajectoryParams params) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YDateUtil.YYYY_MM_DD_HH_MM_SS);
        YDateUtil.getDatePoor(simpleDateFormat.parse(params.getEndTime()),simpleDateFormat.parse(params.getStartTime()));
        long nd = 1000 * 24 * 60 * 60;
        long diff = simpleDateFormat.parse(params.getEndTime()).getTime() - simpleDateFormat.parse(params.getStartTime()).getTime();
        // 计算差多少天
        long day = diff / nd;
        if(day > 7){
            return R.failed("开始时间和结束时间跨度不能超过7天");
        }

        // 根据重点用户查当天用户最新业务详单
        List<OperateAllTrajectoryVo> list = new ArrayList<>();

		List<Map<String, Object>> list1 = importanceOperatorExtendMapper.operateAllTrajectory(params);

		if (params.getId() != null && !("").equals(params.getId())) {
			list1.forEach(stringObjectMap -> {
				if(stringObjectMap.get("clientFreeTime") !=null &&stringObjectMap.get("serverResponseTime") != null){
					stringObjectMap.put("serverResponseTime", String.format("%.2f", Long.parseLong(stringObjectMap.get("serverResponseTime").toString()) / 1000.0));
					stringObjectMap.put("clientTime", String.format("%.2f", ((Long.parseLong(stringObjectMap.get("clientFreeTime").toString())) / 1000.0)));
					stringObjectMap.put("dealTime", String.format("%.2f", Long.parseLong(stringObjectMap.get("dealTime").toString()) / 1000.0));
					OperateAllTrajectoryVo operateAllTrajectoryVo = BeanUtils.mapToObject(stringObjectMap, OperateAllTrajectoryVo.class, Arrays.asList("id"));
					operateAllTrajectoryVo.setId(String.valueOf(stringObjectMap.get("id")));
					list.add(operateAllTrajectoryVo);
				}
			});
		} else {
			list1.forEach(stringObjectMap -> {
				if (stringObjectMap.get("serverResponseTime")!=null){
					stringObjectMap.put("serverResponseTime", String.format("%.2f", Long.parseLong(stringObjectMap.get("serverResponseTime").toString()) / 1000.0));
					stringObjectMap.put("dealTime", String.format("%.2f", Long.parseLong(stringObjectMap.get("dealTime").toString()) / 1000.0));
					OperateAllTrajectoryVo operateAllTrajectoryVo = BeanUtils.mapToObject(stringObjectMap, OperateAllTrajectoryVo.class, Arrays.asList("id"));
					operateAllTrajectoryVo.setId(String.valueOf(stringObjectMap.get("id")));
					list.add(operateAllTrajectoryVo);

				}
			});
		}


        return  R.ok(classifiedData(list, params));
    }


    /**
     * 对数据集按照业务进行分组
     */
    private Object classifiedData(List<OperateAllTrajectoryVo> list, OperateTrajectoryParams params) {

        if(CollectionUtils.isEmpty(list)) { return null; }

        // 获取完整的时间刻度列表(主要要去除最后一个时间点, 因为SQL条件是: < endTime)
        List<String> timeList = YDateUtil.getTimeList(params.getStartTime(), params.getEndTime(), 1);
        List<String> timeResList = new ArrayList<>();
        timeList.remove(timeList.size() - 1);
        if(timeList.size() > 0) {
            for (String s : timeList) {
                timeResList.add(s.substring(0, 19));
            }
        }

        List<List<OperateAllTrajectoryVo>> resList = new ArrayList<>();
        Map<String, List<OperateAllTrajectoryVo>> map = new HashMap<>();
        if (list.size() >0) {
            for (OperateAllTrajectoryVo vo : list) {
                map.computeIfAbsent(vo.getBusinessName(), k -> new ArrayList<>());
                map.get(vo.getBusinessName()).add(vo);
            }
        }

        // 封装数据
		for (Map.Entry<String, List<OperateAllTrajectoryVo>> entry : map.entrySet()) {
			List<OperateAllTrajectoryVo> valueList = entry.getValue();

			resList.add(valueList);
		}

        OperateAllTrajectoryResVo trajectoryVo = new OperateAllTrajectoryResVo();
        trajectoryVo.setLabelTimeList(timeResList);
        trajectoryVo.setResList(resList);

        return trajectoryVo;
    }

    /**
     * 计算两个日期之间的天
     */
    private List<String> getBetweenTime(String startTime, String endTime) throws ParseException {
        List<String> betweenTime = new ArrayList<>();
        Date sdate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTime);
        Date edate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTime);

        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMdd");

        Calendar sCalendar = Calendar.getInstance();
        sCalendar.setTime(sdate);
        int year = sCalendar.get(Calendar.YEAR);
        int month = sCalendar.get(Calendar.MONTH);
        int day = sCalendar.get(Calendar.DATE);
        sCalendar.set(year, month, day, 0, 0, 0);

        Calendar eCalendar = Calendar.getInstance();
        eCalendar.setTime(edate);

        while (sCalendar.before(eCalendar)) {
            betweenTime.add(outFormat.format(sCalendar.getTime()));
            sCalendar.add(Calendar.DAY_OF_YEAR, 1);
        }
        betweenTime.add(outFormat.format(eCalendar.getTime()));

        if (betweenTime.size()==2){
            if (betweenTime.get(0).equals(betweenTime.get(1))){
                betweenTime.remove(1);
            }
        }
        return betweenTime;
    }

    /**
     * 查看重点用户List集合
     */
    @Override
     public List<ImportanceOperator> queryImportanceOperatorList() {
		return this.lambdaQuery()
				.eq(ImportanceOperator::getStatus, 0)
				.orderByAsc(ImportanceOperator::getId)
				.list();
    }

    /**
     * 获取重点用户 Map 集合
     */
    @Override
    public Map<String, ImportanceOperator> getImportanceOperatorMap(List<ImportanceOperator> list) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        Map<String, ImportanceOperator> map = new HashMap<>();
        for (ImportanceOperator operator : list) {
            map.put(operator.getOperatorId(), operator);
        }
        return map;
    }

    /**
     * 获取重点用户Id集合
     */
    public List<String> getImportanceOperatorIds(List<ImportanceOperator> list) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 提取重点用户操作员ID
        return list.stream().map(ImportanceOperator::getOperatorId).collect(Collectors.toList());
    }

    /**
     * 查询用户当天操作的业务code
     */
    @Override
    public R<Object> getBusinessByOperatorId(Integer systemId, String id) {
        // 根据重点用户查当天用户最新业务详单
        List<SearchOptionVo> list = new ArrayList<>();

        try {
			ImportanceOperatorParams params = new ImportanceOperatorParams();
			params.setOperatorId(id);
			params.setSystemId(systemId);
			params.setOrderByColumn("endTime");
			params.setIsAsc("desc");

			// 计算分区
			String partition = PartitionUtil.getPartitionBasedOnTime(DateUtil.formatDateTime(new Date()));

			// 查询数据
			List<RealTimeOperateVo> realTimeOperateVos = importanceOperatorExtendMapper.queryRealTimeOperateList(params, partition);

            // 去重,提取出businessCode
            Set<String> businessCodeSet = new HashSet<>();
			for (RealTimeOperateVo realTimeOperateVo : realTimeOperateVos) {
				if (!businessCodeSet.contains(realTimeOperateVo.getBusinessCode())) {
					businessCodeSet.add(realTimeOperateVo.getBusinessCode());
					SearchOptionVo vo = new SearchOptionVo();
					vo.setLabel(realTimeOperateVo.getBusinessName());
					vo.setCode(realTimeOperateVo.getBusinessCode());
					list.add(vo);
				}
			}

        } catch (Exception e) {
            log.error("重点用户涉及业务code查询出错!", e);
            return R.failed("查询失败");
        }
        return  R.ok(list);
    }

}
